package com.dalonedrow.engine.ui.base.border;

import com.dalonedrow.engine.sprite.base.SimpleVector3;
import com.dalonedrow.engine.sprite.base.SpriteBase;
import com.dalonedrow.engine.sprite.base.SpriteImageObject;
import com.dalonedrow.engine.sprite.base.SpriteImageObjectFactory;
import com.dalonedrow.engine.sprite.impl.BasicLineSpriteObject;
import com.dalonedrow.engine.sprite.impl.BasicQuadSpriteObject;
import com.dalonedrow.engine.sprite.impl.BasicSpriteObject;
import com.dalonedrow.engine.sprite.impl.GroupOfImages;
import com.dalonedrow.engine.sprite.impl.GroupOfLines;
import com.dalonedrow.engine.systems.JOGLErrorHandler;
import com.dalonedrow.engine.systems.Render;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;

/**
 * Abstract class for implementing ui borders comprised of 8 images, a two-color
 * RGBA gradient background, and some white lines.
 * @author DaLoneDrow
 */
public final class Abstract8ImageBorderWithLinesAndGradient extends GuiBorder {
	/** the border group. */
	private GroupOfImages	borders;
	/** the gradient's bottom color. */
	private float[]			gradientBottom;
	/** the gradient's top color. */
	private float[]			gradientTop;
	/** the middle sprite. */
	private GroupOfLines	lines;
	/** the middle sprite. */
	private SpriteBase		middle;
	/** the x-offset for the middle graphic. */
	private int				middleInsetX;
	/** the y-offset for the middle graphic. */
	private int				middleInsetY;
	/**
	 * flag indicating whether supplied offsets are used for middle background.
	 */
	private boolean			useOffsets;
	/**
	 * Creates a new instance of
	 * {@link Abstract8ImageBorderWithLinesAndGradient}.
	 * @param insets the border insets
	 * @param corners the corner images
	 * @param topColor the gradient's top color
	 * @param bottomColor the gradient's bottom color
	 */
	Abstract8ImageBorderWithLinesAndGradient(final int[] insets,
			final String[] corners, final float[] topColor,
			final float[] bottomColor) {
		this(insets, corners, topColor, bottomColor, 0, 0);
	}
	/**
	 * Creates a new instance of {@link Abstract8ImageBorderWithLines}.
	 * @param insets the border insets
	 * @param corners the corner images
	 * @param topColor the gradient's top color
	 * @param bottomColor the gradient's bottom color
	 * @param xOffset the x-offset for the middle background
	 * @param yOffset the y-offset for the middle background
	 */
	Abstract8ImageBorderWithLinesAndGradient(final int[] insets,
			final String[] corners, final float[] topColor,
			final float[] bottomColor, final int xOffset, final int yOffset) {
		final int three = 3, four = 4, eight = 8;
		if (insets == null
				|| insets != null
				&& insets.length != four) {
			super.setInsets(
					eight,
					eight,
					eight,
					eight
					);
		} else {
			super.setInsets(insets);
		}
		if (corners == null
				|| corners != null
				&& corners.length != eight) {
			JOGLErrorHandler.getInstance().fatalError(new Exception(
					"At least 8 images are needed."));
		}
		if (topColor == null
				|| topColor != null
				&& topColor.length != four) {
			JOGLErrorHandler.getInstance().fatalError(new Exception(
					"4-color top gradient is needed."));
		}
		gradientTop = topColor;
		if (bottomColor == null
				|| bottomColor != null
				&& bottomColor.length != four) {
			JOGLErrorHandler.getInstance().fatalError(new Exception(
					"4-color bottom gradient is needed."));
		}
		gradientBottom = bottomColor;
		middleInsetX = xOffset;
		middleInsetY = yOffset;
		try {
			SpriteImageObject imgBL =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_00BOTTOM_LEFT]);
			SpriteImageObject imgB =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_01BOTTOM]);
			SpriteImageObject imgBR =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_02BOTTOM_RIGHT]);
			SpriteImageObject imgTL =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_05TOP_LEFT]);
			SpriteImageObject imgTR =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_07TOP_RIGHT]);
			SpriteImageObject imgT =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_06TOP]);
			SpriteImageObject imgL =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_03LEFT]);
			SpriteImageObject imgR =
					SpriteImageObjectFactory.getInstance().getImageByName(
							corners[GlobalConstants.CORNER_04RIGHT]);
			borders = new GroupOfImages();
			// sprite images don't get set until the preferred size is set
			if (middleInsetX != -1
					&& middleInsetY != -1) {
				useOffsets = true;
			}
			if (middleInsetX == -1) {
				middleInsetX = imgL.getWidth();
			}
			if (middleInsetY == -1) {
				middleInsetY = imgB.getHeight();
			}

			// bottom left
			BasicSpriteObject sb = new BasicSpriteObject();
			sb.setImageRefId(imgBL.getRefId());
			sb.setWidth(imgBL.getWidth());
			sb.setHeight(imgBL.getHeight());
			borders.addImage(sb);
			// bottom middle
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgB.getRefId());
			sb.setHeight(imgB.getHeight());
			borders.addImage(sb);
			// bottom right
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgBR.getRefId());
			sb.setWidth(imgBR.getWidth());
			sb.setHeight(imgBR.getHeight());
			borders.addImage(sb);
			// left
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgL.getRefId());
			sb.setWidth(imgL.getWidth());
			borders.addImage(sb);
			// right
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgR.getRefId());
			sb.setWidth(imgR.getWidth());
			borders.addImage(sb);
			// top left
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgTL.getRefId());
			sb.setWidth(imgTL.getWidth());
			sb.setHeight(imgTL.getHeight());
			borders.addImage(sb);
			// top middle
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgT.getRefId());
			sb.setHeight(imgT.getHeight());
			borders.addImage(sb);
			// top right
			sb = new BasicSpriteObject();
			sb.setImageRefId(imgTR.getRefId());
			sb.setWidth(imgTR.getWidth());
			sb.setHeight(imgTR.getHeight());
			borders.addImage(sb);
			// middle
			middle = new BasicQuadSpriteObject();
			middle.setRed(gradientBottom[0]);
			middle.setGreen(gradientBottom[1]);
			middle.setBlue(gradientBottom[2]);
			middle.setAlpha(gradientBottom[three]);
			middle.setModRed(gradientTop[0]);
			middle.setModGreen(gradientTop[1]);
			middle.setModBlue(gradientTop[2]);
			middle.setModAlpha(gradientTop[three]);
			middle.assignFlag(SpriteBase.FLAG_SPRITE_GRADIENT_VERTICAL_B2T);

			// clear local variables
			sb = null;
			imgTL = null;
			imgT = null;
			imgTR = null;
			imgL = null;
			imgR = null;
			imgBL = null;
			imgB = null;
			imgBR = null;
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void prepareForRendering() throws Exception {
		if (super.isDebug()) {
			middle.setDebug(true);
		}
		Render.getInstance().registerEntity(borders);
		Render.getInstance().registerEntity(middle);
		Render.getInstance().registerEntity(lines);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPosition(final double x, final double y, final double z) {
		super.setPosition(x, y, z);
		final float stepOne = 0.1f, stepTwo = 0.2f;
		borders.setPosition(
				x + middleInsetX,
				y + middleInsetY,
				z + GlobalConstants.CHILD_STEP * stepTwo
				);
		borders.clearFloatStore();
		middle.setPosition(
				x + middleInsetX,
				y + middleInsetY,
				z + GlobalConstants.CHILD_STEP * stepOne
				);
		middle.clearFloatStore();
		lines.setPosition(x, y, z);
		lines.clearFloatStore();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPreferredSize(final int width, final int height) {
		super.setPreferredSize(width, height);
		try {
			// get images
			SpriteImageObject imgBL =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_00BOTTOM_LEFT)
									.getImageRefId()
							);
			SpriteImageObject imgB =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_01BOTTOM)
									.getImageRefId()
							);
			SpriteImageObject imgBR =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_02BOTTOM_RIGHT)
									.getImageRefId()
							);
			SpriteImageObject imgL =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_03LEFT)
									.getImageRefId()
							);
			SpriteImageObject imgR =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_04RIGHT)
									.getImageRefId()
							);
			SpriteImageObject imgTL =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_05TOP_LEFT)
									.getImageRefId()
							);
			SpriteImageObject imgT =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_06TOP)
									.getImageRefId()
							);
			SpriteImageObject imgTR =
					SpriteImageObjectFactory.getInstance().getImageById(
							borders.getImage(
									GlobalConstants.CORNER_07TOP_RIGHT)
									.getImageRefId()
							);
			// set bottom-left position
			borders.getImage(GlobalConstants.CORNER_00BOTTOM_LEFT).setPosition(
					new SimpleVector3(0, 0, 0));
			// set bottom position and width
			borders.getImage(GlobalConstants.CORNER_01BOTTOM).setWidth(
					width - imgBL.getWidth() - imgBR.getWidth());
			borders.getImage(GlobalConstants.CORNER_01BOTTOM).setPosition(
					new SimpleVector3(imgBL.getWidth(), 0, 0));
			// set bottom-right position
			borders.getImage(GlobalConstants.CORNER_02BOTTOM_RIGHT)
					.setPosition(
							new SimpleVector3(width - imgBR.getWidth(), 0, 0));
			// set left position and height
			borders.getImage(GlobalConstants.CORNER_03LEFT).setHeight(
					height - imgBL.getHeight() - imgTL.getHeight());
			borders.getImage(GlobalConstants.CORNER_03LEFT).setPosition(
					new SimpleVector3(0, imgBL.getHeight(), 0));
			// set right position and height
			borders.getImage(GlobalConstants.CORNER_04RIGHT).setHeight(
					height - imgBR.getHeight() - imgTR.getHeight());
			borders.getImage(GlobalConstants.CORNER_04RIGHT).setPosition(
					new SimpleVector3(width - imgR.getWidth()
							, imgBR.getHeight(), 0));
			// set top-left position
			borders.getImage(GlobalConstants.CORNER_05TOP_LEFT).setPosition(
					new SimpleVector3(0, height - imgTL.getHeight(), 0));
			// set top position and width
			borders.getImage(GlobalConstants.CORNER_06TOP).setWidth(
					width - imgTL.getWidth() - imgTR.getWidth());
			borders.getImage(GlobalConstants.CORNER_06TOP)
					.setPosition(
							new SimpleVector3(imgTL.getWidth(), height
									- imgT.getHeight(), 0));
			// set top-right position
			borders.getImage(GlobalConstants.CORNER_07TOP_RIGHT).setPosition(
					new SimpleVector3(width - imgTR.getWidth(),
							height - imgTR.getHeight(), 0));
			// set middle position and width
			if (useOffsets) {
				middle.setWidth(width - middleInsetX * 2);
				middle.setHeight(height - middleInsetY * 2);
			} else {
				middle.setWidth(width - imgL.getWidth() - imgR.getWidth());
				middle.setHeight(height - imgB.getHeight() - imgT.getHeight());
			}
			if (super.getPosition() != null) {
				borders.setPosition(
						super.getPosition().getX(),
						super.getPosition().getY(),
						super.getPosition().getZ()
						);
				borders.clearFloatStore();
				middle.setPosition(
						super.getPosition().getX() + middleInsetX,
						super.getPosition().getY() + middleInsetY,
						super.getPosition().getZ()
						);
				middle.clearFloatStore();
			}
			lines = new GroupOfLines();
			// start 1st line 6px below top
			float x = 2, y = height - 2;
			final float alpha = 0.2f;
			while (y > 2) {
				BasicLineSpriteObject l = new BasicLineSpriteObject();
				l.setAlpha(alpha);
				l.setPosition(x, y, 0);
				l.setHeight(1);
				l.setWidth(width - 2);
				lines.addImage(l);
				y -= 2;
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
}
